#!/usr/bin/python3
# -*- coding: UTF-8 -*-

import tkinter as tk
import threading
import time
import socketserver
import json
import voice
import database as db


# 区域标签字体大小
areaFontSize = 10

# 货物字体大小
stuffFontSize = 8

# 区域标签的长宽尺寸
# 因为区域标签的字体大，所以区域标签和货物标签相同的尺寸，最终会以区域标签最为最终大小
areaLabelWidthSize = 4
areaLabelHightSize = 1

# 货物标签的长宽尺寸
stuffWidth = 4
stuffHight = 3

# 货物编号标签的长宽尺寸
indexWidth = 5
indexHight = 1

# 每个区域货物总数
locationNum = 50

# 每个通道最多支持显示货物的个数
locationPerPassage = 50

# 数据库名称
DB_NAME = "wms.db"


class Area(object):
    """docstring for Area"""
    def __init__(self, window, area, fontsize, width, hight, pos_r, pos_c, r_span, c_span):
        super(Area, self).__init__()

        self.label = tk.Label(window, 
                            text = "%s区" % (area.upper()),
                            font = ('Arial', fontsize),
                            bg = 'SlateGray',
                            width = width,
                            height = hight, )
        self.label.grid(row = pos_r, 
                        # rowspan = r_span,
                        # columnspan = c_span,
                        column = pos_c, 
                        sticky = tk.N + tk.S)


class Passage(object):
    """docstring for Passage"""
    def __init__(self, window, text, fontsize, width, hight, pos_r, pos_c, color):
        super(Passage, self).__init__()

        if color:
            self.label = tk.Label(window, 
                                text = text,
                                font = ('Arial', fontsize),
                                bg = color,
                                width = width,
                                height = hight, )
        else:
            self.label = tk.Label(window, 
                                text = text,
                                font = ('Arial', fontsize),
                                width = width,
                                height = hight, )

        self.label.grid(row = pos_r, 
                        column = pos_c, 
                        sticky = tk.N + tk.S)


class Stuff(object):
    """docstring for Stuff"""
    def __init__(self, window, index, fontsize, pos_r, pos_c, s_width, s_hight):
        super(Stuff, self).__init__()

        self.label = tk.Label(window, 
                                text = "",
                                font = ('Arial', fontsize),
                                bg = 'red',
                                width = s_width,
                                height = s_hight, )
        self.label.grid(row = pos_r, 
                        column = pos_c, 
                        sticky = tk.N + tk.S)

    def SetOnline(self, name):
        self.label.configure(bg = 'green')
        if name:
            self.label.config(text = name)

    def SetOffline(self):
        self.label.configure(bg = 'red')
        self.label.config(text = "")


# total: total location
# lpp: location number pre passage
def PushAreaStuff(stuff, area, passage, total, lpp):
    matrix_r = ord(area.upper()) - ord('A')
    print("Area %c start from passage %d" % (area, passage))

    row = passage * 4
    cnt = 0

    # 偶数区域
    if matrix_r & 0x1 == False:
        while cnt < total:      
            fillnum = min(lpp, total - cnt)

            column = 0
            Area(window, area, areaFontSize, areaLabelWidthSize, areaLabelHightSize, row, column, 0, 0)
            
            column += 1
            for i in range(0, fillnum):
                stuff[matrix_r].append(Stuff(window, i, stuffFontSize, row, column, stuffWidth, stuffHight))
                column += 1

            print("Generate Area %c size %d(%d-%d)done @ row %d!" % (area, total, cnt + 1, cnt + fillnum, row))

            cnt += fillnum
            row += 4
    
    # 奇数区域
    else:
        while cnt < total:
            fillnum = min(lpp, total - cnt)

            column = 0
            Area(window, area, areaFontSize, areaLabelWidthSize, areaLabelHightSize, row + 2, column, 0, 0)
            
            column += 1
            for i in range(0, fillnum):
                stuff[matrix_r].append(Stuff(window, i, stuffFontSize, row + 2, column, stuffWidth, stuffHight))
                column += 1

            print("Generate Area %c size %d(%d-%d)done @ row %d!" % (area, total, cnt + 1, cnt + fillnum, row))

            cnt += fillnum
            row += 4


def PushPassage(passage, total, lpp):
    row = passage * 4
    cnt = 0

    while cnt < total:  
        fillnum = min(lpp, total - cnt)

        column = 0
        Passage(window, '', stuffFontSize, areaLabelWidthSize, indexHight, row + 1, column, "Yellow")
        
        column += 1
        for i in range(cnt + 1, cnt + fillnum + 1):
            Passage(window, "%03d" % i, stuffFontSize, indexWidth, indexHight, row + 1, column, "PaleGreen")
            column += 1

        cnt += fillnum
        row += 4


def PushGap(passage, total, lpp):
    row = passage * 4
    cnt = 0

    while cnt < total:  
        fillnum = min(lpp, total - cnt)

        column = 0
        Passage(window, '', stuffFontSize, areaLabelWidthSize, 1, row + 3, column, "")

        column += 1
        for i in range(cnt + 1, cnt + fillnum + 1):
            Passage(window, '', stuffFontSize, indexWidth, 1, row + 3, column, "")
            column += 1

        cnt += fillnum
        row += 4


class QRCodeRecv(socketserver.BaseRequestHandler):
    def handle(self):
        try:
            while True:
                self.data = self.request.recv(1024)
                # print("{} send:".format(self.client_address), self.data)
                if not self.data:
                    print("connection lost")
                    break
                    
                ParseClientInfo(bytes.decode(self.data))
                # self.request.sendall(self.data.upper())
        except Exception as e:
            print(self.client_address, "disconnect")
        finally:
            self.request.close()

    def setup(self):
        print("before handle, connect with", self.client_address)

    def finish(self):
        print("finish run after handle")


class ServiceThread(threading.Thread):
    """docstring for ServiceThread"""
    def __init__(self):
        super(ServiceThread, self).__init__()
    
    def run(self):
        print("start tcp server")

        addr = ("localhost", 8080)
        self.svr = socketserver.TCPServer(addr, QRCodeRecv)
        self.svr.serve_forever()
        print("serve_forever shutdown")

    def stop_svr(self):
        print("stop tcp server")
        self.svr.shutdown()


def ParseClientInfo(data):
    # print(data)
    info_dict = json.loads(data)
    print(info_dict)

    if 'area' in info_dict and 'num' in info_dict and 'dir' in info_dict:
        area = ord(info_dict['area']) - ord('A')
        index = info_dict['num'] - 1
        direct = info_dict['dir']

        if 'prod' in info_dict:
            name = info_dict['prod']
        else:
            name = None

        print("area %d index %d direct %d name %s" % (area, index, direct, name))

        if direct:
            stuff[area][index].SetOnline(name)
            db.UpdateIntoTable(DB_NAME, area, index, name)
        else:
            stuff[area][index].SetOffline()
            db.DeleteFromTable(DB_NAME, area, index)

        voice.Play(info_dict['area'], info_dict['num'], info_dict['dir'])
    else:
        print("not contain 'area' or 'num' or 'dir'")


try:
    window = tk.Tk()
    window.title('仓库存货 - 看板')

    # window.attributes("-fullscreen", True)
    
    w = window.winfo_screenwidth()
    h = window.winfo_screenheight()
    window.geometry("%dx%d" % (w, h))

    # ======== Area Map - Start ========

    # Area A
    p_num = 0
    stuff = [[]]
    PushAreaStuff(stuff, "A", p_num, locationNum, locationPerPassage)

    PushPassage(p_num, locationNum, locationPerPassage)

    # Area B
    stuff.append([])
    PushAreaStuff(stuff, "B", p_num, locationNum, locationPerPassage)

    PushGap(p_num, locationNum, locationPerPassage);

    # Area C
    p_num += int(locationNum / locationPerPassage) + 1
    stuff.append([])
    PushAreaStuff(stuff, "C", p_num, locationNum, locationPerPassage)

    PushPassage(p_num, locationNum, locationPerPassage)

    # Area D
    stuff.append([])
    PushAreaStuff(stuff, "D", p_num, locationNum, locationPerPassage)

    PushGap(p_num, locationNum, locationPerPassage);

    # ======== Area Map - End ========

    # ======== DataBase - Start ========

    db.CreateTable(DB_NAME)

    t_list = db.SelectTableAll(DB_NAME)
    print(t_list)

    for row in t_list:
        print(row)
        if row[0] > len(stuff):
            print("Area %d invalid maximum %d" % (row[0], len(stuff)))
            continue

        if row[1] > len(stuff[row[0]]):
            print("Area %d index %d invalid maximum %d" % (row[0], row[1], len(stuff[row[0]])))
            continue

        stuff[row[0]][row[1]].SetOnline(row[2])

    # ======== DataBase - End ========

    # Testing data
    
    # stuff[0][1].SetOnline("0x1")
    # stuff[1][0].SetOnline("HSD\n10123\nCZJ")
    # stuff[1][1].SetOnline("1x1")
    # stuff[3][3].SetOnline("3x3")

    service = ServiceThread()
    service.start()
    print("server thread running...")

    window.mainloop()

    service.stop_svr()
    service.join()


except Exception as e:
    raise e

finally:
    pass
